#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LimeReader & LoimReader 版本文件上传工具
基于阿里云OSS2 SDK实现版本文件上传和管理

使用方法:
  python3 upload_to_oss.py [客户端名称]
  python3 upload_to_oss.py --client limereader
  python3 upload_to_oss.py --client all

环境变量:
  ALI_OSS_ACCESS_KEY_ID - 阿里云AccessKey ID
  ALI_OSS_ACCESS_KEY_SECRET - 阿里云AccessKey Secret

作者: Wang Zhen
版本: 2.0.0
日期: 2025
"""

import os
import sys
import json
import logging
import argparse
from datetime import datetime
from pathlib import Path
from typing import Dict, Any, List, Optional

try:
    import oss2
    from oss2.exceptions import OssError
    HAS_OSS = True
except ImportError:
    HAS_OSS = False
    print("警告: 未安装oss2，OSS上传功能将不可用")
    print("安装命令: pip3 install oss2")

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('upload_version.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

class OSSVersionUploader:
    """OSS版本文件上传器"""

    def __init__(self, config_file: str = 'release_config.json'):
        self.config_file = config_file
        self.config = self.load_config()
        self.bucket = None
        self.base_dir = Path('/Users/ethan/Codes/longimagereader/deploy/uploads')

    def load_config(self) -> Dict[str, Any]:
        """加载配置文件"""
        try:
            with open(self.config_file, 'r', encoding='utf-8') as f:
                config = json.load(f)
            logger.info(f"配置文件加载成功: {self.config_file}")
            return config
        except FileNotFoundError:
            logger.error(f"配置文件不存在: {self.config_file}")
            self.create_sample_config()
            sys.exit(1)
        except json.JSONDecodeError as e:
            logger.error(f"配置文件格式错误: {e}")
            sys.exit(1)

    def create_sample_config(self):
        """创建示例配置文件"""
        sample_config = {
            "clients": {
                "LimeReader": {
                    "name": "LimeReader",
                    "directory": "limereader",
                    "prefix": "LimeReader"
                },
                "LoimReader": {
                    "name": "LoimReader",
                    "directory": "loimreader",
                    "prefix": "LoimReader"
                }
            },
            "oss_config": {
                "endpoint": "https://oss-cn-hangzhou.aliyuncs.com",
                "bucket": "limereader-releases",
                "prefix": "updates/",
                "access_key": os.getenv('ALI_OSS_ACCESS_KEY_ID', 'YOUR_ACCESS_KEY'),
                "secret_key": os.getenv('ALI_OSS_ACCESS_KEY_SECRET', 'YOUR_SECRET_KEY')
            }
        }

        with open(self.config_file, 'w', encoding='utf-8') as f:
            json.dump(sample_config, f, indent=2, ensure_ascii=False)

        logger.info(f"示例配置文件已创建: {self.config_file}")
        logger.info("请编辑配置文件或设置环境变量后重新运行")

    def init_oss_connection(self) -> bool:
        """初始化OSS连接"""
        if not HAS_OSS:
            logger.error("OSS2 SDK未安装，无法初始化OSS连接")
            return False

        try:
            oss_config = self.config['oss_config']
            access_key_id = oss_config.get('access_key') or oss_config.get('access_key_id')
            access_key_secret = oss_config.get('secret_key') or oss_config.get('access_key_secret')
            endpoint = oss_config.get('endpoint')
            bucket_name = oss_config.get('bucket') or oss_config.get('bucket_name')

            if not all([access_key_id, access_key_secret, endpoint, bucket_name]):
                logger.error("OSS配置不完整")
                logger.error(f"缺失字段 - access_key: {bool(access_key_id)}, secret_key: {bool(access_key_secret)}, endpoint: {bool(endpoint)}, bucket_name: {bool(bucket_name)}")
                return False

            if access_key_id in ['YOUR_ACCESS_KEY', '', None]:
                logger.error("请配置OSS Access Key ID")
                return False

            if access_key_secret in ['YOUR_SECRET_KEY', '', None]:
                logger.error("请配置OSS Access Key Secret")
                return False

            # 创建Auth对象
            auth = oss2.Auth(access_key_id, access_key_secret)
            self.bucket = oss2.Bucket(auth, endpoint, bucket_name)

            logger.info(f"OSS连接初始化成功: {bucket_name}@{endpoint}")
            return True

        except Exception as e:
            logger.error(f"OSS连接初始化失败: {e}")
            return False

    def get_client_config(self, client_name: str) -> Optional[Dict[str, str]]:
        """获取客户端配置"""
        clients = self.config.get('clients', {})

        # 直接匹配
        if client_name in clients:
            return clients[client_name]

        # 大小写不敏感匹配
        for name, config in clients.items():
            if name.lower() == client_name.lower():
                return config

        return None

    def upload_version_file(self, client_name: str) -> Dict[str, Any]:
        """上传版本文件到OSS"""
        if not self.init_oss_connection():
            return {
                'success': False,
                'error': 'OSS连接失败'
            }

        client_config = self.get_client_config(client_name)
        if not client_config:
            return {
                'success': False,
                'error': f'不支持的客户端: {client_name}'
            }

        client_dir = client_config['directory']
        version_file_path = self.base_dir / client_dir / 'version.json'

        if not version_file_path.exists():
            return {
                'success': False,
                'error': f'版本文件不存在: {version_file_path}'
            }

        try:
            # 验证JSON格式
            with open(version_file_path, 'r', encoding='utf-8') as f:
                version_data = json.load(f)

            # 构建OSS路径
            oss_key = f"updates/{client_dir}/version.json"

            logger.info(f"上传版本文件: {client_name}")
            logger.info(f"本地文件: {version_file_path}")
            logger.info(f"OSS路径: {oss_key}")

            # 上传文件
            with open(version_file_path, 'rb') as f:
                result = self.bucket.put_object(oss_key, f)

            if result.status == 200:
                public_url = f"https://limereader-releases.oss-cn-hangzhou.aliyuncs.com/{oss_key}"
                logger.info(f"✅ {client_name} 版本文件上传成功!")
                logger.info(f"📖 公共访问URL: {public_url}")

                # 验证文件是否可访问
                try:
                    import requests
                    response = requests.get(public_url, timeout=10)
                    if response.status_code == 200:
                        logger.info("✅ 文件可正常访问")
                    else:
                        logger.warning(f"⚠️ 文件可能无法访问 (HTTP {response.status_code})")
                except Exception as e:
                    logger.warning(f"⚠️ 无法验证文件访问性: {e}")

                return {
                    'success': True,
                    'client_name': client_name,
                    'version': version_data.get('latestVersion', 'unknown'),
                    'oss_key': oss_key,
                    'public_url': public_url,
                    'etag': result.headers.get('ETag', '').strip('"')
                }
            else:
                return {
                    'success': False,
                    'client_name': client_name,
                    'error': f'上传失败，状态码: {result.status}'
                }

        except json.JSONDecodeError as e:
            logger.error(f"JSON格式错误: {e}")
            return {
                'success': False,
                'client_name': client_name,
                'error': f'JSON格式错误: {e}'
            }
        except OssError as e:
            logger.error(f"OSS上传失败: {e.status} - {e.message}")
            return {
                'success': False,
                'client_name': client_name,
                'error': f'OSS错误: {e.message}'
            }
        except Exception as e:
            logger.error(f"上传失败: {e}")
            return {
                'success': False,
                'client_name': client_name,
                'error': f'上传失败: {str(e)}'
            }

    def upload_all_clients(self) -> Dict[str, Any]:
        """上传所有客户端版本文件"""
        logger.info("开始批量上传所有客户端版本文件")

        results = {}
        clients = self.config.get('clients', {})

        for client_name in clients.keys():
            logger.info(f"处理客户端: {client_name}")
            result = self.upload_version_file(client_name)
            results[client_name] = result

        # 统计结果
        success_count = sum(1 for r in results.values() if r.get('success', False))
        total_count = len(results)

        logger.info(f"批量上传完成: {success_count}/{total_count} 成功")

        return {
            'success_count': success_count,
            'total_count': total_count,
            'success_rate': f"{success_count}/{total_count}",
            'results': results
        }

def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='LimeReader & LoimReader 版本文件上传工具')
    parser.add_argument('client', nargs='?',
                       choices=['limereader', 'loimreader', 'all'],
                       help='客户端名称 (limereader/loimreader/all)')
    parser.add_argument('--config', default='release_config.json', help='配置文件路径')

    args = parser.parse_args()

    # 解析客户端名称
    client_name = args.client
    if not client_name:
        client_name = 'all'  # 默认上传所有客户端

    print("=" * 60)
    print("     LimeReader & LoimReader 版本文件上传工具")
    print("=" * 60)

    # 检查配置文件或环境变量
    config_file = args.config if args.config else 'release_config.json'
    if not os.path.exists(config_file):
        print("❌ 错误: 配置文件不存在")
        print(f"配置文件路径: {config_file}")
        print("")
        print("请设置以下环境变量:")
        print("  export ALI_OSS_ACCESS_KEY_ID='your_access_key_id'")
        print("  export ALI_OSS_ACCESS_KEY_SECRET='your_access_key_secret'")
        print("")
        print("或者在配置文件中设置OSS配置")
        return 1

    # 尝试从配置文件读取OSS配置
    try:
        with open(config_file, 'r', encoding='utf-8') as f:
            config = json.load(f)
        oss_config = config.get('oss_config', {})

        # 检查配置文件中是否有OSS密钥
        has_config_keys = oss_config.get('access_key') or oss_config.get('access_key_id')
        if not has_config_keys and not (os.getenv('ALI_OSS_ACCESS_KEY_ID') and os.getenv('ALI_OSS_ACCESS_KEY_SECRET')):
            print("❌ 错误: 未配置OSS访问密钥")
            print("")
            print("请设置以下环境变量:")
            print("  export ALI_OSS_ACCESS_KEY_ID='your_access_key_id'")
            print("  export ALI_OSS_ACCESS_KEY_SECRET='your_access_key_secret'")
            print("")
            print(f"或者在配置文件 {config_file} 的 oss_config 中设置:")
            print("  \"access_key\": \"your_access_key_id\"")
            print("  \"secret_key\": \"your_access_key_secret\"")
            return 1

    except Exception as e:
        print(f"❌ 错误: 读取配置文件失败: {e}")
        print("")
        print("请确保配置文件格式正确或设置环境变量")
        return 1

    # 创建上传器
    try:
        uploader = OSSVersionUploader(args.config)

        if client_name == 'all':
            # 批量上传
            print("📤 开始批量上传所有客户端版本文件...")
            print()

            results = uploader.upload_all_clients()

            print()
            print("=" * 60)
            print("上传结果摘要:")
            print("=" * 60)

            for client_name, result in results['results'].items():
                if result.get('success'):
                    print(f"✅ {client_name}: 上传成功")
                    print(f"   版本: {result.get('version', 'N/A')}")
                    print(f"   URL: {result.get('public_url', 'N/A')}")
                    print()
                else:
                    print(f"❌ {client_name}: 上传失败")
                    print(f"   错误: {result.get('error', '未知错误')}")
                    print()

            print(f"总体结果: {results['success_count']}/{results['total_count']} 成功")
            print(f"成功率: {results['success_rate']}")

            if results['success_count'] == results['total_count']:
                print("🎉 所有客户端上传成功!")
            else:
                print("⚠️ 部分客户端上传失败，请检查错误信息")

        else:
            # 单个客户端上传
            print(f"📤 开始上传 {client_name} 版本文件...")
            print()

            result = uploader.upload_version_file(client_name)

            print()
            print("=" * 60)
            print("上传结果:")
            print("=" * 60)

            if result.get('success'):
                print(f"✅ {client_name} 版本文件上传成功!")
                print(f"   版本: {result.get('version', 'N/A')}")
                print(f"   公共URL: {result.get('public_url', 'N/A')}")
                print()
                print("🔗 验证命令:")
                print(f"   curl {result.get('public_url', 'N/A')}")
            else:
                print(f"❌ {client_name} 版本文件上传失败!")
                print(f"   错误: {result.get('error', '未知错误')}")

        return 0

    except KeyboardInterrupt:
        print("\n用户中断操作")
        return 1
    except Exception as e:
        logger.error(f"执行失败: {e}")
        return 1

if __name__ == '__main__':
    sys.exit(main())